#include "CityMap.h"
#include "GFuns.h"

void CityMap::arrangeRoom(sRectangle aRect, int aRoom){
	EObject bedroom[4] = {O_BED, O_WARDROBE, O_TABLE, O_CHAIR};
	EObject kitchen[4] = {O_OVEN, O_BARREL, O_TABLE, O_CHAIR};
	EObject salon[4] = {O_BOOKCASE, O_WARDROBE, O_TABLE, O_CHAIR};
	EObject forge[4] = {O_FURNACE, O_ANVIL, O_BUCKET, OBJECT_NONE};
	EObject herb[4] = {O_HERBSTAND, O_POT, O_TABLE, O_CHAIR};
	EObject warehouse[4] = {O_CHEST, O_CRATE, O_BARREL, OBJECT_NONE};
	EObject* roomSet = NULL;
	if(aRoom == R_BEDROOM) roomSet = bedroom;
	if(aRoom == R_KITCHEN) roomSet = kitchen;
	if(aRoom == R_SALON) roomSet = salon;
	if(aRoom == B_WEAPONSHOP || aRoom == B_ARMORSHOP) roomSet = forge;
	if(aRoom == B_HERBSHOP) roomSet = herb;
	if(aRoom == R_WAREHOUSE) roomSet = warehouse;

	// bed / oven / bookcase
	Node lt = {aRect.x1+1,aRect.y1+1};
	Node rt = {aRect.x2-1,aRect.y1+1};
	Node rb = {aRect.x2-1,aRect.y2-1};
	Node lb = {aRect.x1+1,aRect.y2-1};
	Node bedPos[4] = {lt,rt,rb,lb};
	bool bedPosFlags[4] = {0,0,0,0};
	bool gotIt = false;
	do{
		int myBed = rand()%4;
		bedPosFlags[myBed] = true;
		if(objectsNextTo(bedPos[myBed],O_WALL) != 2 || objectsNextTo(bedPos[myBed],roomSet[0]) != 0) continue;
		bool secBedPosFlags[4] = {0,0,0,0};
		do{
			int secBed = rand()%4;
			secBedPosFlags[secBed] = true;
			if(_BackTiles(bedPos[myBed].x+dir[secBed][0],bedPos[myBed].y+dir[secBed][1]).upper == O_WALL) continue;
			Node secondBed = {bedPos[myBed].x+dir[secBed][0], bedPos[myBed].y+dir[secBed][1]};
			if(objectsNextTo(secondBed,O_WALL) == 1 && objectsNextTo(secondBed,roomSet[0]) == 0){
				_BackTiles(bedPos[myBed].x,bedPos[myBed].y).upper = roomSet[0];
				_BackTiles(bedPos[myBed].x+dir[secBed][0],bedPos[myBed].y+dir[secBed][1]).upper = roomSet[0];

				if(rand()%3 > 0) gotIt = true;
				break;
			}
		} while(!(secBedPosFlags[0] && secBedPosFlags[1] && secBedPosFlags[2] && secBedPosFlags[3]));
		if(gotIt) break;
	}while(!(bedPosFlags[0] && bedPosFlags[1] && bedPosFlags[2] && bedPosFlags[3]));

	// wardrobe / barrel
	vector<Node> possibleWardrobe;
	for(int x=aRect.x1+3; x<=aRect.x2-3; x++){
		Node top = {x,aRect.y1+1};
		Node bottom = {x,aRect.y2-1};
		if(_BackTiles(top.x,top.y).upper == OBJECT_NONE && objectsNextTo(top,O_WALL) == 1)
			possibleWardrobe.push_back(top);
		if(_BackTiles(bottom.x,bottom.y).upper == OBJECT_NONE && objectsNextTo(bottom,O_WALL) == 1)
			possibleWardrobe.push_back(bottom);
	}
	for(int y=aRect.y1+3; y<=aRect.y2-3; y++){
		Node left = {aRect.x1+1,y};
		Node right = {aRect.x2-1,y};
		if(_BackTiles(left.x,left.y).upper == OBJECT_NONE && objectsNextTo(left,O_WALL) == 1)
			possibleWardrobe.push_back(left);
		if(_BackTiles(right.x,right.y).upper == OBJECT_NONE && objectsNextTo(right,O_WALL) == 1)
			possibleWardrobe.push_back(right);
	}
	if(possibleWardrobe.size() > 0){
		for(unsigned int i=0; i<possibleWardrobe.size(); i++){
			int wardrobeNode = rand()%(possibleWardrobe.size());
			_BackTiles(possibleWardrobe[wardrobeNode].x,possibleWardrobe[wardrobeNode].y).upper = roomSet[1];
		}
	}

	// table and chairs
	vector<Node> possibleTable;
	for(int x=aRect.x1+2; x<=aRect.x2-2; x++)
		for(int y=aRect.y1+2; y<=aRect.y2-2; y++){
			int d=0;
			for(; d<8; d++) if(_BackTiles(x+dir_sqr[d][0],y+dir_sqr[d][1]).upper != OBJECT_NONE) break;
			if(d==8){
				Node posTab = {x,y};
				possibleTable.push_back(posTab);
			}
		}
	if(possibleTable.size() > 0){
		int tableNode = rand()%(possibleTable.size());
		_BackTiles(possibleTable[tableNode].x,possibleTable[tableNode].y).upper = roomSet[2];
		for(int d=0; d<4; d++)
			if(rand()%2 == 0)
				_BackTiles(possibleTable[tableNode].x+dir[d][0],possibleTable[tableNode].y+dir[d][1]).upper = roomSet[3];
	}

	// possible spawn points
	vector<Node> freeSpace;
	for(int x=aRect.x1+1; x<=aRect.x2-1; x++)
		for(int y=aRect.y1+1; y<=aRect.y2-1; y++)
		{
			if(_BackTiles(x,y).upper == OBJECT_NONE)
			{
				Node n = {x,y};
				freeSpace.push_back(n);
			}
		}

	// main seller
	int sellerSpace = rand()%freeSpace.size();
	if(aRoom == B_WEAPONSHOP) _BackTiles(freeSpace[sellerSpace].x,freeSpace[sellerSpace].y).spawn = JOB_WEAPONSMITH;
	if(aRoom == B_ARMORSHOP) _BackTiles(freeSpace[sellerSpace].x,freeSpace[sellerSpace].y).spawn = JOB_ARMORSMITH;
	if(aRoom == B_HERBSHOP) _BackTiles(freeSpace[sellerSpace].x,freeSpace[sellerSpace].y).spawn = JOB_HERBALIST;

	// random guys
	for(unsigned int i=0; i<freeSpace.size(); i++)
	{
		int spawn;
		switch(aRoom)
		{
			case R_BEDROOM: spawn = JOB_UNEMPLOYED; break;
			case R_KITCHEN: spawn = JOB_CHEF; break;
			case R_SALON: spawn = JOB_UNEMPLOYED; break;
			case B_WEAPONSHOP: spawn = JOB_WEAPONSMITH; break;
			case B_ARMORSHOP: spawn = JOB_ARMORSMITH; break;
			case B_HERBSHOP: spawn = JOB_HERBALIST; break;
			case R_WAREHOUSE: spawn = JOB_WORKER; break;
		}
		if(rand()%4) spawn = JOB_UNEMPLOYED;

		if(rand()%10 == 0)
		{
			_BackTiles(freeSpace[i].x,freeSpace[i].y).spawn = spawn;
		}
	}
}

void CityMap::placeRandomTrees(){
	for(int x=0; x<_BackTiles.getSizeW(); x++)
		for(int y=0; y<_BackTiles.getSizeH(); y++)
			if(_BackTiles(x,y).lower == F_SOIL && _BackTiles(x,y).upper == OBJECT_NONE)
			{
				if(rand()%4 == 0) _BackTiles(x,y).upper = O_TREE;
			}
}

void CityMap::generatePalace(sRectangle aRect){
	int backTilesX = aRect.x2-aRect.x1;
	int backTilesY = aRect.y2-aRect.y1;
	if(aRect.isVertical()){
		int temp = backTilesX;
		backTilesX = backTilesY;
		backTilesY = temp;
	}
	Tile t;
	t.lower = F_SOIL;
	_BackTiles.build(backTilesX,backTilesY,t);

	int m = 2;
	int sx = m;
	int sy = m;
	int ex = backTilesX-m;
	int ey = backTilesY-m;
	int cx = (sx+ex)/2;
	int cy = (sy+ey)/2;
	
	// king chamber
	int kingW = rand()%2?7:9;
	int kingH = rand()%2?7:9;
	sRectangle king = {cx-kingW/2,ey-kingH,cx+kingW/2,ey};
	placeRectangle(king,O_WALL,F_CARPET);

	// hall
	int hallW = kingW + 6;
	int hallH = kingH + 2;
	sRectangle hall = {cx-hallW/2,ey-2-hallH,cx+hallW/2,ey-2};
	placeRectangle(hall,O_WALL,F_CARPET);

	// clear kings wall
	sRectangle fix = {king.x1+1,ey-2,king.x2-1,ey-2};
	placeRectangle(fix,OBJECT_NONE);

	// left and right wing
	BSP palaceWing;
	sRectangle left = {sx,sy,cx-hallW/2,ey-2};
	sRectangle right = {cx+hallW/2,sy,ex,ey-2};

	vector<sRectangle> leftRooms = palaceWing.produce(left.x1,left.y1,left.x2,left.y2,4);
	placeArea(leftRooms,O_WALL,1);
	vector<sRectangle> rightRooms = palaceWing.produce(right.x1,right.y1,right.x2,right.y2,4);
	placeArea(rightRooms,O_WALL,1);
	placeRectangle(left,O_WALL,F_CARPET);
	placeRectangle(right,O_WALL,F_CARPET);

	// doors
	_BackTiles(cx-hallW/2,ey-3).upper = OBJECT_NONE;
	_BackTiles(cx+hallW/2,ey-3).upper = OBJECT_NONE;
	_BackTiles(cx,ey-2-hallH).upper = OBJECT_NONE;
	_BackTiles(cx,ey-kingH).upper = OBJECT_NONE;

	// path
	sRectangle trees = {cx-1,sy-m+1,cx+1,ey-2-hallH-3};
	sRectangle path = {cx,sy-m,cx,ey-2-hallH-1};
	placeRectangle(trees,O_TREE);
	placeRectangle(path,O_ROAD);

	// arranging kings chamber
	_BackTiles(cx-kingW/2+1,ey-2).upper = O_PLANT;
	_BackTiles(cx+kingW/2-1,ey-2).upper = O_PLANT;
	_BackTiles(cx-kingW/2+2,ey-1).upper = O_PLANT;
	_BackTiles(cx+kingW/2-2,ey-1).upper = O_PLANT;
	_BackTiles(cx,ey-4).upper = O_THRONE;
	_BackTiles(cx-1,ey-3).upper = O_CANDLESTICK;
	_BackTiles(cx+1,ey-3).upper = O_CANDLESTICK;
	for(int y=ey-5; y>ey-kingH; y-=2){
		_BackTiles(cx-kingW/2+2,y).upper = O_ARMOR;
		_BackTiles(cx+kingW/2-2,y).upper = O_ARMOR;
	}

	// spawn
	_BackTiles(cx,ey-5).spawn = JOB_KING;
	_BackTiles(cx-1,ey-hallH-3).spawn = JOB_SOLDIER;
	_BackTiles(cx+1,ey-hallH-3).spawn = JOB_SOLDIER;
	_BackTiles(cx-1,ey-kingH-1).spawn = JOB_SOLDIER;
	_BackTiles(cx+1,ey-kingH-1).spawn = JOB_SOLDIER;

	// arranging hall
	for(int y=ey-4; y>ey-2-hallH; y-=2){
		_BackTiles(cx-hallW/2+1,y).upper = O_ARMOR;
		_BackTiles(cx+hallW/2-1,y).upper = O_ARMOR;
	}
	for(int x=cx-hallW/2+1; x<cx+hallW/2; x+=2){
		if(x!=cx) _BackTiles(x,ey-1-hallH).upper = O_PLANT;
	}

	// arranging wings
	EBuilding rooms[3] = {R_BEDROOM, R_KITCHEN, R_SALON};
	for(unsigned int s=0; s<leftRooms.size(); s++)
		arrangeRoom(leftRooms[s],rooms[rand()%3]);
	for(unsigned int s=0; s<rightRooms.size(); s++)
		arrangeRoom(rightRooms[s],rooms[rand()%3]);

	if(aRect.isVertical()){
		if((aRect.x1+aRect.x2)/2 < _tilesX/2) flipBackTiles(false); 
		pasteBackTiles(aRect,true);
	}
	else{
		if((aRect.y1+aRect.y2)/2 < _tilesY/2) flipBackTiles(false);
		pasteBackTiles(aRect,false);
	}
}

void CityMap::generateTemple(sRectangle aRect){
	int backTilesX = aRect.x2-aRect.x1;
	int backTilesY = aRect.y2-aRect.y1;
	if(aRect.isVertical()){
		int temp = backTilesX;
		backTilesX = backTilesY;
		backTilesY = temp;
	}
	Tile t;
	t.lower = F_SOIL;
	_BackTiles.build(backTilesX,backTilesY,t);
	Tab2D<Tile>& b = _BackTiles;

	int m = 2;
	int sx = m;
	int sy = m;
	int ex = backTilesX-m;
	int ey = backTilesY-m;
	if((ey-sy)%2 == 1) ey++;
	int cx = (sx+ex)/2;
	int cy = (sy+ey)/2;

	// walls
	int baseEndX = ex-(ey-sy)/2;
	sRectangle base = {sx+2,sy,baseEndX,ey};
	placeRectangle(base,O_WALL,F_STONE);
	sRectangle entrance = {sx,cy-2,sx+2,cy+2};
	placeRectangle(entrance,O_WALL,F_STONE);
	b(sx+2,cy-1).upper = OBJECT_NONE;
	b(sx+2,cy).upper = OBJECT_NONE;
	b(sx+2,cy+1).upper = OBJECT_NONE;
	b(sx,cy).upper = OBJECT_NONE;
	for(int x=baseEndX+1; x<=ex; x++){
		for(int y=sy+(x-baseEndX)-1; y<=ey-(x-baseEndX)+1; y++){
			b(x,y).upper = OBJECT_NONE;
			b(x,y).lower = F_STONE;
		}
		b(x,sy+(x-baseEndX)).upper = O_WALL;
		b(x,ey-(x-baseEndX)).upper = O_WALL;
		b(x,sy+(x-baseEndX)-1).upper = O_WALL;
		b(x,ey-(x-baseEndX)+1).upper = O_WALL;
	}
	for(int y=sy+1; y<ey; y++) if(b(baseEndX,y).upper == O_WALL) b(baseEndX,y).upper = OBJECT_NONE;

	// spawn
	b(baseEndX+2,cy).spawn = JOB_PRIEST;
	int believers = randInt(25,75);

	// objects
	for(int r=0; r<m; r++)	b(r,cy).upper = O_ROAD;
	b(baseEndX+1,cy).upper = O_ALTAR;
	b(baseEndX+1,cy+1).upper = O_ALTAR;
	b(baseEndX+1,cy-1).upper = O_ALTAR;
	b(baseEndX,cy+3).upper = O_CANDLESTICK;
	b(baseEndX,cy-3).upper = O_CANDLESTICK;
	for(int x=sx+4; x<baseEndX-1; x+=2)
	{
		b(x-1,sy+1).upper = O_PLANT;
		b(x-1,ey-1).upper = O_PLANT;
		for(int y=sy+3; y<ey-2; y++)
		{
			if(y!=cy)
			{
				b(x,y).upper = O_BENCH;
				if(rand()%100 < believers) b(x+1,y).spawn = JOB_UNEMPLOYED;
			}
		}
	}
	b(baseEndX-1,sy+1).upper = O_CANDLESTICK;
	b(baseEndX-1,ey-1).upper = O_CANDLESTICK;

	placeRandomTrees();

	// place it
	if(aRect.isVertical()){
		if((aRect.y1+aRect.y2)/2 < _tilesY/2) flipBackTiles(true); 
		pasteBackTiles(aRect,true);
	}
	else{
		if((aRect.x1+aRect.x2)/2 < _tilesX/2) flipBackTiles(true);
		pasteBackTiles(aRect,false);
	}
}

void CityMap::generateShop(sRectangle aRect, int aShop){
	int backTilesX = aRect.x2-aRect.x1;
	int backTilesY = aRect.y2-aRect.y1;
	Tile t;
	t.lower = F_SOIL;
	_BackTiles.build(backTilesX,backTilesY,t);
	Tab2D<Tile>& b = _BackTiles;

	int m = 2;
	int sx = m;
	int sy = m;
	int ex = backTilesX-m;
	int ey = backTilesY-m;
	int cx = (sx+ex)/2;
	int cy = (sy+ey)/2;
	sRectangle rect = {sx,sy,ex,ey};

	// walls
	BSP shop;
	vector<sRectangle> walls = shop.produce(sx,sy,ex,ey,(backTilesX*backTilesY)/10);
	placeArea(walls,O_WALL,true);
	placeRectangle(rect,O_WALL,F_WOOD);

	// doors, path and sign
	EObject sign;
	switch(aShop){
	case B_WEAPONSHOP: sign = O_SIGN_WEAPON; break;
	case B_ARMORSHOP: sign = O_SIGN_ARMOR; break;
	case B_HERBSHOP: sign = O_SIGN_HERB; break;
	}
	int doorsX, doorsY;
	bool possibleDirs[4] = {1,1,1,1};
	if(aRect.x1 == -1) possibleDirs[0] = false;
	if(aRect.y1 == -1) possibleDirs[1] = false;
	if(aRect.x2 == _tilesX) possibleDirs[2] = false;
	if(aRect.y2 == _tilesY) possibleDirs[3] = false;
	while(true){
		int myDir = rand()%4;
		if(!possibleDirs[myDir]) continue;
		switch(myDir){
		case 0: //left
			doorsX = 0;
			doorsY = randInt(3,backTilesY-3);
			b(doorsX+1,doorsY).upper = O_ROAD;
			b(doorsX+2,doorsY).upper = OBJECT_NONE;
			b(doorsX+3,doorsY).upper = OBJECT_NONE;
			b(doorsX+1,doorsY-1).upper = sign;
			break;
		case 1: //up
			doorsX = randInt(3,backTilesX-3);
			doorsY = 0;
			b(doorsX,doorsY+1).upper = O_ROAD;
			b(doorsX,doorsY+2).upper = OBJECT_NONE;
			b(doorsX,doorsY+3).upper = OBJECT_NONE;
			b(doorsX+1,doorsY+1).upper = sign;
			break;
		case 2: //right
			doorsX = backTilesX;
			doorsY = randInt(3,backTilesY-3);
			b(doorsX-1,doorsY).upper = O_ROAD;
			b(doorsX-2,doorsY).upper = OBJECT_NONE;
			b(doorsX-3,doorsY).upper = OBJECT_NONE;
			b(doorsX-1,doorsY+1).upper = sign;
			break;
		case 3: //down
			doorsX = randInt(3,backTilesX-3);
			doorsY = backTilesY;
			b(doorsX,doorsY-1).upper = O_ROAD;
			b(doorsX,doorsY-2).upper = OBJECT_NONE;
			b(doorsX,doorsY-3).upper = OBJECT_NONE;
			b(doorsX-1,doorsY-1).upper = sign;
			break;
		}
		break;
	}

	// arrange
	for(unsigned int w=0; w<walls.size(); w++){
		if(w==1 || (w>5 && !(w%2))) arrangeRoom(walls[w],R_WAREHOUSE);
		else if(w==3) arrangeRoom(walls[w],R_KITCHEN);
		else if(w==4) arrangeRoom(walls[w],R_BEDROOM);
		else arrangeRoom(walls[w],aShop);
	}

	placeRandomTrees();

	// place it
	pasteBackTiles(aRect,false);
}

void CityMap::generateInn(sRectangle aRect){
	int backTilesX = aRect.x2-aRect.x1;
	int backTilesY = aRect.y2-aRect.y1;
	if(aRect.isVertical()){
		int temp = backTilesX;
		backTilesX = backTilesY;
		backTilesY = temp;
	}
	Tile t;
	t.lower = F_SOIL;
	_BackTiles.build(backTilesX,backTilesY,t);

	int m = 2;
	int sx = m;
	int sy = m;
	int ex = backTilesX-m-1;
	int ey = backTilesY-m-1;
	int cx = (sx+ex)/2;
	int cy = (sy+ey)/2;

	// bedrooms
	BSP rooms;
	int by = randInt(sy+4,ey-4);
	sRectangle rect = {sx,by,ex,ey};
	vector<sRectangle> bedrooms = rooms.produce(rect,(backTilesX*backTilesY)/10);
	placeArea(bedrooms,O_WALL,true);
	placeRectangle(rect,O_WALL,F_WOOD);

	// reception
	int recW = 8;
	int recX = randInt(sx,ex-recW);
	sRectangle reception = {recX,sy,recX+recW,by};
	placeRectangle(reception,O_WALL,F_WOOD);

	// doors
	int counter = 0;
	while(counter++<20){
		int doorsX = randInt(recX+2,recX+recW-2);
		if(_BackTiles(doorsX,by+1).upper == OBJECT_NONE){
			_BackTiles(doorsX,by).upper = OBJECT_NONE;
			break;
		}
	}
	_BackTiles(recX+4,0).upper = O_ROAD;
	_BackTiles(recX+4,1).upper = O_ROAD;
	_BackTiles(recX+5,1).upper = O_SIGN_INN;
	_BackTiles(recX+4,2).upper = OBJECT_NONE;

	// reception arrange
	_BackTiles(recX+2,sy+1).upper = O_RECEPTION;
	_BackTiles(recX+2,sy+2).upper = O_RECEPTION;
	_BackTiles(recX+recW-1,sy+1).upper = O_PLANT;
	_BackTiles(recX+recW-1,by-1).upper = O_PLANT;
	_BackTiles(recX+recW-3,(by+sy)/2).upper = O_TABLE;
	for(int d=0; d<4; d++) _BackTiles(recX+recW-3+dir[d][0],(by+sy)/2+dir[d][1]).upper = O_CHAIR;

	// spawn
	_BackTiles(recX+1,sy+1).spawn = JOB_BARTENDER;
	for(int x = recX+2; x<recX+recW; x++)
	{
		for(int y = sy+1; y<by; y++)
		{
			if((_BackTiles(x,y).upper == OBJECT_NONE || _BackTiles(x,y).upper == O_CHAIR) && rand()%7 == 0)
			{
				_BackTiles(x,y).spawn = JOB_UNEMPLOYED;
			}
		}
	}

	// rooms arrange
	for(unsigned int w=0; w<bedrooms.size(); w++){
		if(w==1) arrangeRoom(bedrooms[w],R_KITCHEN);
		else arrangeRoom(bedrooms[w],R_BEDROOM);
	}

	placeRandomTrees();

	// place inn
	if(aRect.isVertical()){
		if((aRect.x1+aRect.x2)/2 < _tilesX/2) flipBackTiles(false); 
		pasteBackTiles(aRect,true);
	}
	else{
		if((aRect.y1+aRect.y2)/2 < _tilesY/2) flipBackTiles(false);
		pasteBackTiles(aRect,false);
	}
}

void CityMap::generateHouse(sRectangle aRect){
	int backTilesX = aRect.x2-aRect.x1;
	int backTilesY = aRect.y2-aRect.y1;
	Tile t;
	t.lower = F_SOIL;
	_BackTiles.build(backTilesX,backTilesY,t);
	Tab2D<Tile>& b = _BackTiles;

	int m = 2;
	int sx = m;
	int sy = m;
	int ex = backTilesX-m;
	int ey = backTilesY-m;
	int cx = (sx+ex)/2;
	int cy = (sy+ey)/2;
	sRectangle rect = {sx,sy,ex,ey};

	// walls
	BSP house;
	vector<sRectangle> walls = house.produce(rect,aRect.area()/20);
	placeArea(walls,O_WALL,true);
	placeRectangle(rect,O_WALL,F_WOOD);

	// doors and path
	int doorsX, doorsY;
	bool possibleDirs[4] = {1,1,1,1};
	if(aRect.x1 == -1) possibleDirs[0] = false;
	if(aRect.y1 == -1) possibleDirs[1] = false;
	if(aRect.x2 == _tilesX) possibleDirs[2] = false;
	if(aRect.y2 == _tilesY) possibleDirs[3] = false;
	while(true){
		int myDir = rand()%4;
		if(!possibleDirs[myDir]) continue;
		switch(myDir){
		case 0: //left
			doorsX = 0;
			doorsY = randInt(3,backTilesY-3);
			b(doorsX+1,doorsY).upper = O_ROAD;
			b(doorsX+2,doorsY).upper = OBJECT_NONE;
			b(doorsX+3,doorsY).upper = OBJECT_NONE;
			break;
		case 1: //up
			doorsX = randInt(3,backTilesX-3);
			doorsY = 0;
			b(doorsX,doorsY+1).upper = O_ROAD;
			b(doorsX,doorsY+2).upper = OBJECT_NONE;
			b(doorsX,doorsY+3).upper = OBJECT_NONE;
			break;
		case 2: //right
			doorsX = backTilesX;
			doorsY = randInt(3,backTilesY-3);
			b(doorsX-1,doorsY).upper = O_ROAD;
			b(doorsX-2,doorsY).upper = OBJECT_NONE;
			b(doorsX-3,doorsY).upper = OBJECT_NONE;
			break;
		case 3: //down
			doorsX = randInt(3,backTilesX-3);
			doorsY = backTilesY;
			b(doorsX,doorsY-1).upper = O_ROAD;
			b(doorsX,doorsY-2).upper = OBJECT_NONE;
			b(doorsX,doorsY-3).upper = OBJECT_NONE;
			break;
		}
		break;
	}

	int rooms[] = {R_BEDROOM,R_KITCHEN,R_WAREHOUSE,R_SALON};
	// arrange
	for(unsigned int i=0; i<walls.size(); i++){
		if(i==0) arrangeRoom(walls[i],R_BEDROOM);
		else if(i==1) arrangeRoom(walls[i],R_KITCHEN);
		else if(i==2) arrangeRoom(walls[i],R_WAREHOUSE);
		else if(i==3) arrangeRoom(walls[i],R_SALON);
		else arrangeRoom(walls[i],rooms[rand()%4]);
	}

	placeRandomTrees();

	// place it
	pasteBackTiles(aRect,false);
}

void CityMap::generateGraveyard(sRectangle aRect){
	for(int x=aRect.x1+2; x<aRect.x2-1; x+=2)
		for(int y=aRect.y1+2; y<aRect.y2-1; y+=2)
		{
			if(rand()%10 > 0)
			{
				setUpper(x,y,O_GRAVE);
				if(rand()%6 == 0 && y != aRect.y2-2) setSpawn(x,y+1,JOB_UNEMPLOYED);
			}
		}

	int exitX = (aRect.x1 + aRect.x2)/2;
	if(getUpper(exitX,aRect.y1+2) == O_GRAVE || getUpper(exitX,aRect.y2-2) == O_GRAVE)
		exitX++;

	for(int x=aRect.x1+1; x<aRect.x2; x++)
		for(int y=aRect.y1+1; y<aRect.y2; y++){
				if(x == exitX) continue;

				if(x == aRect.x1+1 || x == aRect.x2-1
				|| y == aRect.y1+1 || y == aRect.y2-1)
					setUpper(x,y,O_FENCE);
		}

}

void CityMap::generateMarket(sRectangle aRect){
	for(int x=aRect.x1; x<=aRect.x2; x++)
		for(int y=aRect.y1; y<=aRect.y2; y++)
			setLower(x,y,F_MARKET);

	setUpper(aRect.x1+1,aRect.y1+1,O_ARMOR);
	setUpper(aRect.x2-1,aRect.y1+1,O_ARMOR);
	setUpper(aRect.x1+1,aRect.y2-1,O_ARMOR);
	setUpper(aRect.x2-1,aRect.y2-1,O_ARMOR);

	int counter = 0;
	while(counter++<aRect.area()/4){
		// marketstand
		int len = randInt(1,3);

		int fx = randInt(aRect.x1+len, aRect.x2-len);
		int fy = randInt(aRect.y1+len, aRect.y2-len);
		int px = fx+len;
		int py = fy;
		if(rand()%2){
			px = fx;
			py = fy+len;
		}
		bool areaClear = true;
		for(int x=fx-1; x<=px+1; x++)
			for(int y=fy-1; y<=py+1; y++)
				if(getUpper(x,y) != OBJECT_NONE) areaClear = false;
		if(areaClear)
		{
			vector<Node> possibleSpawns;
			for(int x=fx; x<=px; x++)
				for(int y=fy; y<=py; y++)
				{
					setUpper(x,y, O_MARKETSTAND);
					for(int d=0; d<4; d++)
						if(getUpper(x+dir[d][0],y+dir[d][1]) == OBJECT_NONE)
						{
							Node n = {x+dir[d][0],y+dir[d][1]};
							possibleSpawns.push_back(n);
						}
				}

			while(true)
			{
				unsigned int i;
				for(i=0; i<possibleSpawns.size(); i++)
				{
					int x = possibleSpawns[i].x;
					int y = possibleSpawns[i].y;
					if(getUpper(x,y) != OBJECT_NONE || getSpawn(x,y) != JOB_NONE)
					{
						possibleSpawns.erase(possibleSpawns.begin() + i);
						break;
					}
				}
				if(i >= possibleSpawns.size()) break;
			}

			int randSpawn = randInt(0,possibleSpawns.size()-1);
			int x = possibleSpawns[randSpawn].x;
			int y = possibleSpawns[randSpawn].y;
			setSpawn(x,y,JOB_SELLER);
		}

		// wheel
		if(rand()%6 == 0){
			fx = randInt(aRect.x1+1, aRect.x2-1);
			fy = randInt(aRect.y1+1, aRect.y2-1);
			areaClear = true;
			for(int x=fx-1; x<=fx+1; x++)
				for(int y=fy-1; y<=fy+1; y++)
					if(getUpper(x,y) != OBJECT_NONE) areaClear = false;
			if(areaClear)	setUpper(fx,fy, O_WELL);
		}
	}

	// random spawns
	for(int x=aRect.x1+1; x<aRect.x2-1; x++)
		for(int y=aRect.y1+1; y<aRect.y2-1; y++)
			if(getUpper(x,y) == OBJECT_NONE && rand()%6 == 0)
			{
				int job;
				do{
					job = randInt(JOB_UNEMPLOYED,JOB_END-1);
				} while(job == JOB_KING || job == JOB_PRIEST);
				setSpawn(x,y,job);
			}
}